# -*- coding: utf-8 -*-

import numpy as np
import weakref
import single
import muti

class MoveObject(object):

    def GetPos(self):
        return np.array([0.0, 0.0])
    
    def GetV(self):
        return 0


class Purser(MoveObject):
    
    def SetTarget(self, pos):
        return
    
    def GetRMin(self):
        return 0.0
    
    def GetRMax(self):
        return 0.0
    
    def GetInPoints(self):
        return np.zeros((0, 2))


class Manager(object):

    def __init__(self):
        self.pursers = []
        self.escaper = None
        self.elpcache = None
    
    def SetEscaper(self, e):
        self.escaper = e
        e.manager = weakref.ref(self)
    
    def SetPursers(self, plst):
        self.pursers = plst
        for p in plst:
            p.manager = weakref.ref(self)
        self.elpcache = [None] * len(self.pursers)
    
    def OnUpdateTarget(self, purser):
        ix = self.pursers.index(purser)
        if self.elpcache is None:
            purser.SetTarget(None)
            return
        elp = self.elpcache[ix]
        if elp is None:
            purser.SetTarget(None)
            return
        purser.SetTarget(elp)

    def IsQuit(self):
        e_pos = self.escaper.GetPos()
        for p in self.pursers:
            p_pos = p.GetPos()
            r = np.linalg.norm(p_pos - e_pos)
            if r <= 0.3:
                return True
        return False
    
    def InitState(self):
        cache = muti.State(len(self.pursers))
        cache.e_pos = self.escaper.GetPos()
        cache.e_vmax = self.escaper.GetV()
        for i, p in enumerate(self.pursers):
            cache.p_pos[i] = p.GetPos()
            cache.p_vmax[i] = p.GetV()
        return cache

    def MainLoop(self):
        cache = self.InitState()
        try:
            anglelst = muti.SolveState3(cache)
        except BaseException as e:
            print(e)
            anglelst = [0.0] * cache.p_n
        for i in range(len(self.pursers)):
            if anglelst[i] > np.pi / 6:
                anglelst[i] = np.pi / 6
            elif anglelst[i] < - np.pi / 6:
                anglelst[i] = -np.pi / 6
        aim1 = cache.p_pos.copy()
        for i, p in enumerate(self.pursers):
            a = anglelst[i]
            if np.abs(a) >= 0.01:
                aim1[i, :] = muti.Rotate(
                    cache.p_pos[i],
                    cache.e_pos,
                    anglelst[i]
                )
            else:
                aim1[i, :] = cache.e_pos.copy()
            path = single.GetPath(cache.p_pos[i], aim1[i])
            if single.GetTriByPos(path[0]) == single.GetTriByPos(path[-1]):
                aim1[i] = cache.e_pos.copy()
        subject_points = np.zeros((0, 2))
        ix = muti.GetOrder(cache)
        for i, p in enumerate(self.pursers):
            subject_points = np.vstack((subject_points, p.GetInPoints()))
        for i in ix:
            p = self.pursers[i]
            elp, sample = single.GetTarget(
                cache.p_pos[i],
                aim1[i],
                subject_points,
                p.GetRMax(),
                p.GetRMin(),
                p.GetInPoints()
            )
            if elp is None:
                continue
            self.elpcache[i] = elp
            x, y = sample
            seg = x.shape[0]
            xy = np.zeros((seg, 2))
            xy[:, 0] = x
            xy[:, 1] = y
            subject_points = np.vstack((subject_points, xy))